#include "Utilities.h"
#include <time.h>

#ifdef NZOS_IOS
#include <sys/time.h>
#else
#include <sys/timeb.h>
#endif //end NZOS_IOS

#include "Evaluation.h"

namespace Nezha
{

#ifdef NZOS_IOS

	static timeval gsInitialValue;
	static bool gsInitialValueAssaigned = false;

	s64 GetTimeMicroseconds()
	{
		if (!gsInitialValueAssaigned)
		{
			gettimeofday(&gsInitialValue, 0);
			gsInitialValueAssaigned = true;
		}

		struct timeval currentTime;
		gettimeofday(&currentTime, 0);

		struct timeval deltaTime;
		timersub(&currentTime, &gsInitialValue, &deltaTime);

		return 1000000*deltaTime.tv_sec + deltaTime.tv_usec;
	}

	u32 GetTimeMillisecond()
	{
		if (!gsInitialValueAssaigned)
		{
			gettimeofday(&gsInitialValue, 0);
			gsInitialValueAssaigned = true;
		}

		struct timeval currentTime;
		gettimeofday(&currentTime, 0);

		struct timeval deltaTime;
		timersub(&currentTime, &gsInitialValue, &deltaTime);

		return 1000*deltaTime.tv_sec + deltaTime.tv_usec / 1000;
	}

#else

	static long gsInitialSec = 0;
	static long gsInitialMSec = 0;
	static long gsInitialUSec = 0;
	static bool gsInitialValueAssaigned = false;

	s64 GetTimeMicroseconds()
	{
		struct timeb currentTime;

		if (!gsInitialValueAssaigned)
		{
			ftime(&currentTime);
			gsInitialSec = (long)currentTime.time;
			gsInitialMSec = currentTime.millitm;
			gsInitialUSec = 1000*currentTime.millitm;
			gsInitialValueAssaigned = true;
		}

		ftime(&currentTime);
		long currentSec = (long)currentTime.time;
		long currentUSec = 1000*currentTime.millitm;
		long deltaSec = currentSec - gsInitialSec;
		long deltaUSec = currentUSec - gsInitialUSec;
		if (deltaUSec < 0)
		{
			deltaUSec += 1000000;
			--deltaSec;
		}

		return 1000000*deltaSec + deltaUSec;
	}

	u32 GetTimeMillisecond()
	{
		struct timeb currentTime;

		if (!gsInitialValueAssaigned)
		{
			ftime(&currentTime);
			gsInitialSec = (long)currentTime.time;
			gsInitialMSec = currentTime.millitm;
			gsInitialUSec = 1000*currentTime.millitm;
			gsInitialValueAssaigned = true;
		}

		ftime(&currentTime);
		long currentSec = (long)currentTime.time;
		long currentMSec = currentTime.millitm;
		long deltaSec = currentSec - gsInitialSec;
		long deltaMSec = currentMSec - gsInitialMSec;
		if (deltaMSec < 0)
		{
			deltaMSec += 1000;
			--deltaSec;
		}

		return 1000*deltaSec + deltaMSec;
	}

#endif //end NZOS_IOS


	Real GetTimeSeconds()
	{
		u32 ms = GetTimeMillisecond();
		return (Real)1e-03 * ms;
	}

	void GetLocalTimeString(String& str)
	{
		time_t ltime;
		time(&ltime);
		str = ctime(&ltime);
	}

	void GetLocalTimeInfo(LocalTime& lt)
	{
		time_t ltime;
		time(&ltime);
		struct tm* t = localtime(&ltime);

		lt.Sec = t->tm_sec;
		lt.Min = t->tm_min;
		lt.Hour = t->tm_hour;
		lt.Day = t->tm_mday;
		lt.Month = t->tm_mon;
		lt.Year = t->tm_year + 1900;
		lt.DayInAWeek = t->tm_wday;
	}

	void StringUtil::Trim(_string& str, bool left /* = true */, bool right /* = true */)
	{
		const _string delims = "\t\r";
		if(right)
		{
			str.erase(str.find_last_not_of(delims) + 1);
		}
		
		if(left)
		{
			str.erase(0, str.find_first_not_of(delims));
		}
	}

	void StringUtil::Split(const _string& str, StringArray& arr, const _string& delims /* = "" */,
		u32 maxSplits /* = 0 */, bool preserveDelims /* = false */)
	{
		arr.clear();
		arr.reserve(maxSplits > 0 ? maxSplits + 1 : 8);

		u32 numSplits = 0;

		size_t start, pos;
		start = 0;
		do 
		{
			pos = str.find_first_of(delims, start);
			if (pos == start)
			{
				// Do nothing
				start = pos + 1;
			}
			else if (pos == String::npos || (maxSplits && numSplits == maxSplits))
			{
				// Copy the rest of the string
				arr.push_back( str.substr(start) );
				break;
			}
			else
			{
				// Copy up to delimiter
				arr.push_back( str.substr(start, pos - start) );

				if(preserveDelims)
				{
					// Sometimes there could be more than one delimiter in a row.
					// Loop until we don't find any more delims
					size_t delimStart = pos, delimPos;
					delimPos = str.find_first_not_of(delims, delimStart);
					if (delimPos == String::npos)
					{
						// Copy the rest of the string
						arr.push_back( str.substr(delimStart) );
					}
					else
					{
						arr.push_back( str.substr(delimStart, delimPos - delimStart) );
					}
				}

				start = pos + 1;
			}
			// parse up to next real data
			start = str.find_first_not_of(delims, start);
			++numSplits;

		} while (pos != String::npos);
	}

	//////////////////////////////////////////////////////////////////////////
	// string hash functions

	u32 ElfHash(const char *str, bool uppercase) 
	{ 
		u32 hash = 0;
		u32 x = 0;
		const char *p = str;

		if(uppercase)
		{
			while(*p)
			{
				hash = (hash << 4) + toupper(*p);
				if ((x = hash & 0xF0000000L ) != 0)
				{
					hash ^= (x >> 24);
					hash &= ~ x;
				}
				p++;
			}
		}
		else
		{
			while(*p) 
			{
				hash = (hash << 4) + *p++;
				if ((x = hash & 0xF0000000L ) != 0)
				{
					hash ^= (x >> 24);
					hash &= ~ x;
				}
			}
		}

		return (hash & 0x7FFFFFFF);
	}

	u32 FNVHash(const char *str, bool uppercase) 
	{ 
		const char *p = str;
		u32 hash = 0;

		if(uppercase)
		{
			while(*p)
			{
				hash *= 16777619;
				hash ^= (u32)((u8)(toupper(*p)));
				p++;
			}
		}
		else
		{
			while(*p)
			{
				hash *= 16777619;
				hash ^= (u32)((u8)(*p++));
			}
		}

		return hash; 
	}

	u32 SimpleHash(const char *str, bool uppercase) 
	{ 
		u32 h;
		const u8 *p;

		if(uppercase)
		{
			for(h=0, p = (const u8*)str; *p; p++)
				h = 31 * h + toupper(*p);
		}
		else
		{
			for(h=0, p = (const u8*)str; *p; p++)
				h = 31 * h + *p;
		}

		return h; 
	} 


	const RGBA RGBA::BLACK(0.0, 0.0, 0.0, 0.0);
	const RGBA RGBA::WHITE(1.0, 1.0, 1.0, 1.0);
	const RGBA RGBA::RED(1.0, 0.0, 0.0, 1.0);
	const RGBA RGBA::GREEN(0.0, 1.0, 0.0, 1.0);
	const RGBA RGBA::BLUE(0.0, 0.0, 1.0, 1.0);
	const RGBA RGBA::INVALID(-1, -1, -1, -1);

	ColorDW RGBA::getDW_ARGB() const
	{
		u32 tmp;
		u32 argb = 0;

		tmp = (u32)((u8)a * 255);
		argb = tmp << 24;

		tmp = (u32)((u8)r * 255);
		argb += tmp << 16;

		tmp = (u32)((u8)g * 255);
		argb += tmp << 8;

		tmp = (u32)((u8)b * 255);
		argb += tmp;

		return argb;
	}

	ColorDW RGBA::getDW_RGBA() const
	{
		u32 tmp;
		u32 argb = 0;

		tmp = (u32)((u8)r * 255);
		argb = tmp << 24;

		tmp = (u32)((u8)g * 255);
		argb += tmp << 16;

		tmp = (u32)((u8)b * 255);
		argb += tmp << 8;

		tmp = (u32)((u8)a * 255);
		argb += tmp;

		return argb;
	}

	//const u16 PrimeNumber::msPrimeNumbersBelow1000[] =
	//{
	//	2, 3, 5, 7, 11, 13, 17, 19, 23, 29,
	//	31, 37, 41, 43, 47, 53, 59, 61, 67, 71,
	//	73, 79, 83, 89, 97, 101, 103, 107, 109, 113,
	//	127, 131, 137, 139, 149, 151, 157, 163, 167, 173,
	//	179, 181, 191, 193, 197, 199, 211, 223, 227, 229,
	//	233, 239, 241, 251, 257, 263, 269, 271, 277, 281,
	//	283, 293, 307, 311, 313, 317, 331, 337, 347, 349,
	//	353, 359, 367, 373, 379, 383, 389, 397, 401, 409,
	//	419, 421, 431, 433, 439, 443, 449, 457, 461, 463,
	//	467, 479, 487, 491, 499, 503, 509, 521, 523, 541,
	//	547, 557, 563, 569, 571, 577, 587, 593, 599, 601,
	//	607, 613, 617, 619, 631, 641, 643, 647, 653, 659,
	//	661, 673, 677, 683, 691, 701, 709, 719, 727, 733,
	//	739, 743, 751, 757, 761, 769, 773, 787, 797, 809,
	//	811, 821, 823, 827, 829, 839, 853, 857, 859, 863,
	//	877, 881, 883, 887, 907, 911, 919, 929, 937, 941,
	//	947, 953, 967, 971, 977, 983, 991, 997
	//};

	bool PrimeNumber::Test(u32 n)
	{
		if(n < 2)
			return false;


		if((n % 2) == 0)
		{
			return false;
		}

		// sqrt(n) >= n / 2 start at n = 9, so we don't need to compute sqrtn
		// until 13
		if(n <= 11)
		{
			return n == 2 || n == 3 || n == 5 || n == 7 || n == 11;
		}

		u32 sqrt_n = (u32)Sqrt((float)n);

		// ignore even number.
		for(u32 i = 3; i < sqrt_n; i += 2)
		{
			if(n % i == 0)
				return false;
		}

		return true;
	}

	u32 PrimeNumber::MakePrimeGreaterThan(u32 n)
	{
		bool oddNumber = (n % 2 != 0);

		// make it odd
		u32 m = oddNumber ? n + 2 : n + 1;

		while(1)
		{
			if(Test(m))
			{
				break;
			}

			m += 2;
		}

		return m;
	}

	u32 PrimeNumber::MakePrimeLessThan(u32 n)
	{
		bool oddNumber = (n % 2 != 0);

		// make it odd
		u32 m = oddNumber ? n - 2 : n - 1;

		while(m > 2)
		{
			if(Test(m))
			{
				break;
			}

			m -= 2;
		}

		return 0;
	}

	u32 NZRandom::msSeed = 0;

	void NZRandom::SetSeed(u32 seed)
	{
		if(seed == 0)
		{
			msSeed = GetTimeMillisecond();
		}
		else
		{
			msSeed = seed;
		}

		srand(msSeed);
	}

	int NZRandom::Rangei(int iMin, int iMax)
	{
		// very simply and happy method from HGE.
		msSeed = 214013 * msSeed + 2531011;
		return iMin + (msSeed ^ msSeed>>15)%(iMax - iMin + 1);
	}

	float NZRandom::Rangef(float fMin, float fMax)
	{
		msSeed = 214013 * msSeed + 2531011;
		return fMin + (msSeed>>16)*(1.0f/65535.0f)*(fMax - fMin);
	}

}//end namespace Nezha